package com.buer.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.buer.Listener.ExcelOriginDataListener;
import com.buer.dao.dmo.ExcelOriginDataEntity;
import com.buer.dao.dmo.ExportExcelDto;
import com.buer.dao.dmo.FingerPrintBG1Entity;
import com.buer.dao.dmo.LastSheetDto;
import com.buer.dao.dmo.originDataProcess.GroupB;
import com.buer.dao.enums.ResponseCodeEnum;
import com.buer.service.dto.BuerResult;
import com.buer.service.dto.EachSheetDataDto;
import com.buer.service.dto.uploadExcelRsp.SheetBriefInfoDto;
import com.buer.service.dto.uploadExcelRsp.UploadExelRspDto;
import com.buer.service.intf.FingerPrintGB1Service;
import com.buer.service.intf.PreLoadingRateService;
import com.buer.service.util.ListUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

@Controller
@RequestMapping("preLoadingRate")
public class PreLoadingRateController {
    /**
     * 日志工具
     */
    private static Logger LOG = LoggerFactory.getLogger(PreLoadingRateController.class);

    @Autowired
    private FingerPrintGB1Service fingerPrintGB1Service;

    @Autowired
    private PreLoadingRateService preLoadingRateService;

    private ExcelOriginDataListener excelOriginDataListener;

    private String excelFileName;

    /**
     * 展示页面
     *
     * @param request
     * @return
     */
    @RequestMapping(value = {"/preLoadingRate", "/"})
    public ModelAndView preLoadingRate(HttpServletRequest request) {
        try {
            ModelAndView mv = new ModelAndView("preLoadingRate/preLoadingRate.ftl");
            return mv;

        } catch (Exception e) {
            LOG.error("进入preLoadingRate页面异常，e={}", e);
            ModelAndView mv = new ModelAndView("error.ftl");
            mv.addObject("activeIndex", "1");
            mv.addObject("activeName", "1");
            return mv;
        }
    }

    /**
     * 上传Excel，获取到Excel的原始数据
     *
     * @param file
     * @param response
     */
    @ResponseBody
    @RequestMapping(value = "/uploadExcelFile", method = RequestMethod.POST)
    public UploadExelRspDto uploadExcelFile(@RequestParam("file") MultipartFile file,
                                            HttpServletResponse response) {
        UploadExelRspDto uploadExelRspDto = new UploadExelRspDto();
        excelOriginDataListener = new ExcelOriginDataListener();
        try {
            excelFileName = file.getOriginalFilename();
            uploadExelRspDto.setRespCode(ResponseCodeEnum.SUCCESS.code);
            uploadExelRspDto.setRespMsg("上传文件：" + excelFileName + ResponseCodeEnum.SUCCESS.msg);
            // 0. 要是为空，返回错误
            if (file.isEmpty()) {
                uploadExelRspDto.setRespCode(ResponseCodeEnum.SUCCESS.code);
                uploadExelRspDto.setRespMsg("failed to upload " + excelFileName + " because the file was empty.");
                LOG.info("failed to upload " + excelFileName + " because the file was empty.");
                return uploadExelRspDto;
            }

            // 1. 获取所有Excel的原始数据，存到originDataMap
            ExcelReader excelReader = EasyExcel.read(file.getInputStream(), ExcelOriginDataEntity.class, excelOriginDataListener).build();
            Map<Integer, EachSheetDataDto> originDataMap = new HashMap<Integer, EachSheetDataDto>();
            try {
                List<ReadSheet> readSheets = excelReader.excelExecutor().sheetList();
                for (ReadSheet sheet : readSheets) {
                    excelReader.read(sheet);
                }
                originDataMap = excelOriginDataListener.originDataMap;
            } catch (Exception e) {
                LOG.error("获取到原始数据originDataMap异常e={}", e);
                excelReader.finish();
            }

            // 2. 检查sheetName是否配置文件中的velocity
            List<FingerPrintBG1Entity> fingerPrintBG1List = fingerPrintGB1Service.obtainFingerPrintGB1FromConfFile();
            for (Map.Entry<Integer, EachSheetDataDto> entry : originDataMap.entrySet()) {
                String sheetName = entry.getValue().getSheetName();
                boolean containSheetName = false;
                for (FingerPrintBG1Entity ele : fingerPrintBG1List) {
                    if (ele.getVelocity().toString().equals(sheetName)) {
                        containSheetName = true;
                        break;
                    }
                }
                if (!containSheetName) {
                    uploadExelRspDto.setRespCode(ResponseCodeEnum.INPUT_ILLEGAL.code);
                    uploadExelRspDto.setRespMsg("第" + entry.getValue().getSheetNo() + "张表的sheetName为：\"" + sheetName + "\",在配置中没有velocity与此相同");
                    LOG.info("failed to upload " + excelFileName + " because the file was empty.");
                    return uploadExelRspDto;
                }
            }

            // 3.对每一个sheet进行预处理
            for (Entry<Integer, EachSheetDataDto> sheet : originDataMap.entrySet()) {
                preLoadingRateService.tellGroupAOrB(sheet.getValue());
                preLoadingRateService.tellGroupADetial(sheet.getValue());
                preLoadingRateService.dealGroupBProcess1(sheet.getValue());
            }

            // 4. 返回结果
            uploadExelRspDto.setRespCode(ResponseCodeEnum.SUCCESS.code);
            uploadExelRspDto.setRespMsg("success to upload " + excelFileName);
            for (Entry<Integer, EachSheetDataDto> sheet : originDataMap.entrySet()) {
                uploadExelRspDto.getSheetInfo().add(new SheetBriefInfoDto(sheet.getValue().getSheetNo(), sheet.getValue().getSheetName()));
            }
            LOG.info("success to upload " + excelFileName);
            return uploadExelRspDto;

        } catch (Exception e) {
            LOG.error("uploadExcelFile异常，e={}", e);
            ModelAndView mv = new ModelAndView("error.ftl");
            mv.addObject("activeIndex", "1");
            mv.addObject("activeName", "1");
            uploadExelRspDto.setRespCode(ResponseCodeEnum.ERROR.code);
            uploadExelRspDto.setRespMsg(e.getMessage());
            return uploadExelRspDto;
        }
    }

    @RequestMapping(value = "downloadTempExcelFile", method = RequestMethod.GET)
    public void downloadExcelFile(HttpServletResponse response) {

        try {
            download(false, response);
        } catch (Exception e) {
            LOG.error("downloadExcelFile异常，e={}", e);

        }


    }

    @RequestMapping(value = "submitGaisiVal", method = RequestMethod.POST)
    @ResponseBody
    public BuerResult submitGaisiVal(@RequestBody JSONObject requestBody,
                                     HttpServletResponse respons) {

        String info = String.valueOf(requestBody.get("sheetInfo"));
        List<SheetBriefInfoDto> sheetInfo = JSON.parseArray(info, SheetBriefInfoDto.class);
        List<FingerPrintBG1Entity> fingerPrintBG1EntityList = fingerPrintGB1Service.obtainFingerPrintGB1FromConfFile();
        BuerResult buerResult = new BuerResult();

        // 给出高斯值之后，求每一个sheet的分组B 的 F{ velocity }值
        for (Map.Entry<Integer, EachSheetDataDto> sheetData : excelOriginDataListener.originDataMap.entrySet()) {
            EachSheetDataDto eachSheetDataDto = sheetData.getValue();
            // 根据velocity，查fingerPrint_GB1.txt中的force
            Integer velocity = Integer.valueOf(eachSheetDataDto.getSheetName());
            Integer force = null;
            for (FingerPrintBG1Entity entity : fingerPrintBG1EntityList) {
                if (Math.abs(entity.getVelocity() - velocity) == 0) {
                    force = entity.getForce();
                    break;
                }
            }
            if (null == force) {
                buerResult.setResponseCode(ResponseCodeEnum.ERROR.code);
                buerResult.setResponseMsg("velocity" + velocity + "在配置表中不存在");
                return buerResult;
            }

            // a= force/b
            Float a = null;
            for (SheetBriefInfoDto sheetBriefInfo : sheetInfo) {
                if (Math.abs(sheetBriefInfo.getSheetNo() - eachSheetDataDto.getSheetNo()) == 0) {
                    a = Float.valueOf(force) / Float.valueOf(sheetBriefInfo.getGaoSiVal());
                    break;
                }
            }
            if (null == a) {
                buerResult.setResponseCode(ResponseCodeEnum.ERROR.code);
                buerResult.setResponseMsg("sheetNo:" + eachSheetDataDto.getSheetNo() + "  在提交的json中未找到");
                return buerResult;
            }


            // F{ velocity }=a* ForcePeakValue
            for (GroupB groupB : eachSheetDataDto.getGroupBList()) {
                // 根据DeltaLValues 在origin中Max(ForcePeakValue)
                Float deltaLValues = groupB.getDeltaLValues();
                Float maxForcePeakValue = groupB.getForcePeakValue();
                for (ExcelOriginDataEntity originDataEntity : eachSheetDataDto.getSheetOriginDataList()) {
                    if (Math.abs(originDataEntity.getDeltaLValues() - deltaLValues) == 0) {
                        maxForcePeakValue = Math.max(maxForcePeakValue, originDataEntity.getForcePeakValue());
                    }
                }

                groupB.setF(a * maxForcePeakValue);
            }

        }

        //返回成功
        buerResult.setResposeInfo(ResponseCodeEnum.SUCCESS);
        return buerResult;


    }

    @RequestMapping(value = "downloadResultExcelFile", method = RequestMethod.GET)
    public void downloadResultExcelFile(HttpServletResponse response) {

        try {
            // 输出
            download(true, response);
        } catch (Exception e) {
            LOG.error("downloadResultExcelFilee异常，e={}", e);

        }


    }

    /**
     * 下载Excel
     *
     * @param downloadLastFile 是否是下载最终的文件
     * @param response
     * @throws IOException
     */
    private void download(Boolean downloadLastFile, HttpServletResponse response) throws IOException {

        String fileNamePrefix=downloadLastFile?"result_":"tmp_";
        String fileName = URLEncoder.encode(fileNamePrefix + excelFileName, "UTF-8");

        // 这里注意 有同学反应下载的文件名不对。这个时候 请别使用swagger 他会有影响
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        Map<Integer, EachSheetDataDto> originDataMap = excelOriginDataListener.originDataMap;

        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系

        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), GroupB.class).build();
        // 分别去写每一个sheet
        for (Map.Entry<Integer, EachSheetDataDto> originSheetData : originDataMap.entrySet()) {
            Integer sheetNo = originSheetData.getKey();
            EachSheetDataDto originSheetDataValue = originSheetData.getValue();
            WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo, originSheetDataValue.getSheetName()).head(ExportExcelDto.class).build();

            excelWriter.write(preLoadingRateService.buildExportExcelDto(originSheetDataValue), writeSheet);
        }

        // 对于下载最终结果的file还需要整理下
        if(downloadLastFile){
            // 写出总共的sheet
            // 1. 先获取到所有的需要输出的数据
            List<LastSheetDto> lastSheetDtos = new ArrayList<LastSheetDto>();
            for (Map.Entry<Integer, EachSheetDataDto> sheetDto : originDataMap.entrySet()) {
                for (GroupB groupB : sheetDto.getValue().getGroupBList()) {
                    lastSheetDtos.add(new LastSheetDto(groupB.getLr(), groupB.getF()));
                }
            }

            // 2. 对lastSheetDtos按照lr升序排列
            ListUtils.sort(lastSheetDtos, true, "groupBLr");

            // 3. 写最后一个sheet
            List<List<String>> lastHead = lastHead(originDataMap);
            WriteSheet writeSheet = EasyExcel.writerSheet(originDataMap.size() + 1, "总结").head(lastHead).build();
            List<List<Object>> lastSheetDataList = lastSheetDataList(lastSheetDtos, originDataMap.size());
            excelWriter.write(lastSheetDataList, writeSheet);
        }

        /// 千万别忘记finish 会帮忙关闭流
        excelWriter.finish();

    }


    /**
     * 最后一个sheet的表头
     *
     * @return
     */
    private List<List<String>> lastHead(Map<Integer, EachSheetDataDto> originDataMap) {
        List<List<String>> list = new ArrayList<List<String>>();

        for (Entry<Integer, EachSheetDataDto> ele: originDataMap.entrySet()) {
            List<String> head0 = new ArrayList<String>();
            head0.add("lr" + ele.getValue().getSheetName());
            list.add(head0);
            List<String> head1 = new ArrayList<String>();
            head1.add("f" + ele.getValue().getSheetName());
            list.add(head1);
        }

        return list;
    }

    /**
     * 最后一个sheet的数据
     *
     * @return
     */
    private List<List<Object>> lastSheetDataList(List<LastSheetDto> lastSheetDtos, Integer colSize) {
        List<List<Object>> list = new ArrayList<List<Object>>();
        // 共有数据条数
        int dataSize = lastSheetDtos.size();
        Integer rowSize = (int) Math.ceil((double) dataSize / colSize);

        for (int row = 0; row < rowSize; row++) {
            // 每一行数据,oneRow
            ArrayList<Object> oneRow = new ArrayList<Object>();
            for (int col = 0; col < colSize; col++) {
                int dataIndex = rowSize * col + row;
                if (dataIndex < dataSize) {
                    oneRow.add(lastSheetDtos.get(dataIndex).getGroupBLr());
                    oneRow.add(lastSheetDtos.get(dataIndex).getGroupBF());
                }
            }
            list.add(oneRow);
        }
        return list;
    }


    /**
     * 动态头，实时生成头写入，加入velocity
     *
     * @return
     */
    private List<List<String>> headCommon() {
        List<String> emptyHead = new ArrayList<String>();
        emptyHead.add("");

        List<List<String>> list = new ArrayList<List<String>>();
        List<String> head0 = new ArrayList<String>();
        head0.add("Name");
        List<String> head1 = new ArrayList<String>();
        head1.add("pValues");
        List<String> head2 = new ArrayList<String>();
        head2.add("LValues");
        List<String> head3 = new ArrayList<String>();
        head3.add("ForcePeakValue");
        List<String> head4 = new ArrayList<String>();
        head4.add("DeltaLValues");
        List<String> head5 = new ArrayList<String>();
        head5.add("AX");
        List<String> head6 = new ArrayList<String>();
        head6.add("Ay");
        List<String> head7 = new ArrayList<String>();
        head7.add("Bx");

        List<String> head9 = new ArrayList<String>();
        head9.add("ForcePeakValue");
        List<String> head10 = new ArrayList<String>();
        head10.add("DeltaLValues");
        List<String> head11 = new ArrayList<String>();
        head11.add("AX");
        List<String> head12 = new ArrayList<String>();
        head12.add("Ay");
        List<String> head13 = new ArrayList<String>();
        head13.add("Bx");
        List<String> head14 = new ArrayList<String>();
        head14.add("k");
        List<String> head15 = new ArrayList<String>();
        head15.add("lr");
        List<String> head16 = new ArrayList<String>();
        head16.add("ForcePeakValue");

        List<String> head18 = new ArrayList<String>();
        head18.add("ForcePeakValue");
        List<String> head19 = new ArrayList<String>();
        head19.add("ForcePeakValue");
        List<String> head20 = new ArrayList<String>();
        head20.add("ForcePeakValue");
        List<String> head21 = new ArrayList<String>();
        head21.add("ForcePeakValue");
        List<String> head22 = new ArrayList<String>();
        head22.add("ForcePeakValue");
        List<String> head23 = new ArrayList<String>();
        head23.add("ForcePeakValue");
        List<String> head24 = new ArrayList<String>();
        head24.add("ForcePeakValue");
        List<String> head25 = new ArrayList<String>();
        head25.add("ForcePeakValue");
        list.add(head0);
        list.add(head1);
        list.add(head2);
        list.add(head3);
        list.add(head4);
        list.add(head5);
        list.add(head6);
        list.add(head7);
        list.add(emptyHead);
        list.add(head9);
        list.add(head10);
        list.add(head11);
        list.add(head12);
        list.add(head13);
        list.add(head14);
        list.add(head15);
        list.add(head16);
        list.add(emptyHead);
        list.add(head18);
        list.add(head19);
        list.add(head20);
        list.add(head21);
        list.add(head22);
        list.add(head23);
        list.add(head24);
        list.add(head25);
        return list;
    }

}
